package com.jiang.operator;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.jiang.entity.Block;
import com.jiang.entity.PeerNetwork;
import com.jiang.storage1.Node;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class WorkProof implements Runnable{
    private static final Logger LOGGER = LoggerFactory.getLogger(WorkProof.class);
    public static boolean flag = false;
    private Block oldBlock;
    private String[] vac;
    public Block newBlock;
    private Node node;
    public PeerNetwork peerNetwork;//这个起着重要的作用
    public File dataFile;

    public WorkProof(Block oldBlock, String[] vac, Node node, PeerNetwork peerNetwork, File dataFile) {
        this.oldBlock = oldBlock;
        this.vac = vac;
        this.node = node;
        this.peerNetwork = peerNetwork;
        this.dataFile = dataFile;
    }

    @Override
    public void run() {
        //进行计算
        newBlock = generateBlock();

    }

    public Block generateBlock() {
        Gson gson = new GsonBuilder().create();
        /**
         * 在这里面修改吗，就是每个节点算出自己的目标值，然后还有命中率
         */
        Block newBlock = new Block();
        newBlock.setIndex(oldBlock.getIndex() + 1);
        newBlock.setTimestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        newBlock.setVac(vac);
        newBlock.setMerkleRoot(BlockUtils.hashMerkle(Arrays.asList(vac)));
        newBlock.setDifficulty(1);//暂且先设为1
        newBlock.setPrevHash(oldBlock.getHash());
        for(int i = 0;!flag;i++){//这个其实也可以无穷，但是为了序号有用
            String hex = String.format("%x", i);//%x整数类型（十六进制），按照十六进制的格式
            newBlock.setNonce(hex);//随机数无限增加
            try {
                LOGGER.info("计算出"+convert(BlockUtils.calculateHash(newBlock).substring(0,7)) % 10000000);
                LOGGER.info("转换为十进制："+convert(BlockUtils.calculateHash(newBlock).substring(0,7)));
                //获得上一块区块生成的时间
                if(convert(BlockUtils.calculateHash(newBlock).substring(0,7)) % 10000000 > node.getGoal(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(oldBlock.getTimestamp()).getTime())){
                    //查看计算得到的字符串是否是需要的，也就是困难数没有计算成功，需要再次计算
                    if((BlockChain.blockChain.size() - 1) == newBlock.getIndex()){
                        break;
                    }
                    LOGGER.info("目标值："+node.getGoal(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(oldBlock.getTimestamp()).getTime()));
                    LOGGER.info("{} need to do more work!", convert(BlockUtils.calculateHash(newBlock).substring(0, 7))%7000000);
                    /**
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        LOGGER.error("error", e);
                        Thread.currentThread().interrupt();//该线程停止
                    }*/
                }else{
                    //计算成功之后，将该计算成功的hash设置为新块的hash
                    LOGGER.info("目标值："+node.getGoal(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(oldBlock.getTimestamp()).getTime()));
                    LOGGER.info("{} work done!", BlockUtils.calculateHash(newBlock));
                    newBlock.setHash(BlockUtils.calculateHash(newBlock));
                    break;
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        if(flag){
            return null;
        }
        flag = true;
        newBlock.setHash(BlockUtils.calculateHash(newBlock));
        BlockChain.blockChain.add(newBlock);
        node.setTokens(node.getTokens()+1);
        try {
            FileUtils.writeStringToFile(dataFile, "\n"+gson.toJson(newBlock), StandardCharsets.UTF_8, true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        peerNetwork.broadcast("NEWBLOCK "+gson.toJson(newBlock));
        LOGGER.info("Success mine!");
        return newBlock;
    }

    public int convert(String content){
        int number = 0;
        String[] HighLetter = {"a", "b", "c", "d", "e", "f"};
        Map<String,Integer> map = new HashMap<>();
        for(int i = 0;i <= 9;i++){
            map.put(i+"",i);
        }
        for(int j= 10;j<HighLetter.length+10;j++){
            map.put(HighLetter[j-10],j);
        }
        String[]str = new String[content.length()];
        for(int i = 0; i < str.length; i++){
            str[i] = content.substring(i,i+1);
        }
        for(int i = 0; i < str.length; i++){
            number += map.get(str[i])*Math.pow(16,str.length-1-i);
        }
        return number;
    }
}
